package api

import (
	"github.com/graphql-go/graphql"
	"ozonTest/internal/domain/comments/model"
	"ozonTest/internal/domain/comments/service"
	model2 "ozonTest/internal/domain/posts/model"
	service2 "ozonTest/internal/domain/posts/service"
	"time"
)

// Объявляем тип Comment без поля replies
var commentType = graphql.NewObject(graphql.ObjectConfig{
	Name: "Comment",
	Fields: graphql.Fields{
		"id": &graphql.Field{
			Type: graphql.Int,
		},
		"post_id": &graphql.Field{
			Type: graphql.Int,
		},
		"parent_id": &graphql.Field{
			Type: graphql.Int,
		},
		"content": &graphql.Field{
			Type: graphql.String,
		},
		"created_at": &graphql.Field{
			Type: graphql.DateTime,
		},
	},
})

// После объявления устанавливаем поле replies
func init() {
	commentType.AddFieldConfig("replies", &graphql.Field{
		Type: graphql.NewList(commentType),
	})
}

// Определение типа Post
var postType = graphql.NewObject(graphql.ObjectConfig{
	Name: "Post",
	Fields: graphql.Fields{
		"id": &graphql.Field{
			Type: graphql.Int,
		},
		"title": &graphql.Field{
			Type: graphql.String,
		},
		"content": &graphql.Field{
			Type: graphql.String,
		},
		"comments_enabled": &graphql.Field{
			Type: graphql.Boolean,
		},
		"created_at": &graphql.Field{
			Type: graphql.DateTime,
		},
	},
})

// Определение Query
var QueryType = graphql.NewObject(graphql.ObjectConfig{
	Name: "Query",
	Fields: graphql.Fields{
		"post": &graphql.Field{ // пост с комментариями
			Type: graphql.NewObject(graphql.ObjectConfig{
				Name: "PostWithComments",
				Fields: graphql.Fields{
					"post":     &graphql.Field{Type: postType},
					"comments": &graphql.Field{Type: graphql.NewList(commentType)},
				},
			}),
			Args: graphql.FieldConfigArgument{
				"id": &graphql.ArgumentConfig{
					Type: graphql.Int,
				},
			},
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				id, _ := p.Args["id"].(int)
				postsService := p.Context.Value("postsService").(service2.PostsService)
				post, comments, err := postsService.GetPostWithCommentsByID(id)
				if err != nil {
					return nil, err
				}

				info := make(map[string]interface{})
				info["post"] = post
				info["comments"] = comments

				return info, nil
			},
		},
		"posts": &graphql.Field{
			Type: graphql.NewList(postType),
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				postsService := p.Context.Value("postsService").(service2.PostsService)
				return postsService.GetAllPosts()
			},
		},
	},
})

// Определение Mutation
var MutationType = graphql.NewObject(graphql.ObjectConfig{
	Name: "Mutation",
	Fields: graphql.Fields{
		"createPost": &graphql.Field{
			Type: postType,
			Args: graphql.FieldConfigArgument{
				"title": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"content": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"comments_enabled": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.Boolean),
				},
			},
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				post := &model2.Post{
					Title:           p.Args["title"].(string),
					Content:         p.Args["content"].(string),
					CommentsEnabled: p.Args["comments_enabled"].(bool),
					CreatedAt:       time.Now(),
				}
				postsService := p.Context.Value("postsService").(service2.PostsService)
				err := postsService.CreatePost(post)
				return post, err
			},
		},
		"addComment": &graphql.Field{
			Type: commentType,
			Args: graphql.FieldConfigArgument{
				"post_id": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.Int),
				},
				"content": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"parent_id": &graphql.ArgumentConfig{
					Type: graphql.Int,
				},
			},
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				comment := &model.Comment{
					PostID:    p.Args["post_id"].(int),
					Content:   p.Args["content"].(string),
					ParentID:  nil,
					CreatedAt: time.Now(),
				}
				if parentID, ok := p.Args["parent_id"].(int); ok {
					comment.ParentID = &parentID
				}
				commentsService := p.Context.Value("commentsService").(service.CommentsService)
				err := commentsService.AddComment(comment)
				return comment, err
			},
		},
	},
})
